/**
 * PHOSIDE: PHosphorylation Site IDentification Engine.
 * Copyright 2009 Digital Biology Lab, University of Missouri.
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3 of the License, or (at your option) any later
 * version. <p/> This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more
 * details.
 */

package phoside.classify.result;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import phoside.PhosphoProteins;
import phoside.PhosphoProteins.PhosphoType;
import phoside.Protein;

import phoside.data.feature.extaction.InstancesExtractorFromProteins;
import phoside.data.feature.model.Instance;

import phoside.util.StaticFinalValues;

/**
 *
 * @author gjj
 */
public class ResultUtil {

    public static boolean resetResultInterpreter(PhosidePredictionResult result,
            PhosphoProteins groundTruth) {
        Set<PhosphoType> types = new HashSet();
        double minScore = Double.MAX_VALUE;
        Iterator<Protein> it = result.proteinIterator();
        while (it.hasNext()) {
            Protein protein = it.next();
            String acc = protein.getAccession();
            String seq = protein.getSequence();
            List<Double> preds = result.getPredictions(acc);

            if (preds==null)
                continue;

            int n = preds.size();
            for (int i=0; i<n; i++) {
                if (!Double.isInfinite(preds.get(i))) {
                    PhosphoType type = PhosphoType.valueOfByAA(seq.charAt(i));
                    if (type!=null) {
                        types.add(type);
                        if (minScore>preds.get(i)) {
                            minScore = preds.get(i);
                        }
                    }
                }
            }
        }

        if (types.isEmpty())
            return false;

        // roc
        InstancesExtractorFromProteins insExtractor =
                new InstancesExtractorFromProteins(groundTruth, null, types, 0, InstancesExtractorFromProteins.PhosphoTag.PHOSPHO);
        List<Instance> instances_positive = insExtractor.fetch(-1);
        insExtractor = new InstancesExtractorFromProteins(groundTruth, null, types, 0, InstancesExtractorFromProteins.PhosphoTag.NONPHOSPHO);
        List<Instance> instances_unlabeled = insExtractor.fetch(-1);

        List<Double> label = new ArrayList();
        List<Double> pred = new ArrayList();

        for (Instance ins : instances_positive) {
            Protein protein = (Protein)ins.getInstanceTag().getTag(StaticFinalValues.INSTANCETAGNAMEPROTEIN);
            String acc = protein.getAccession();
            String seq = protein.getSequence();
            int site = (Integer)ins.getInstanceTag().getTag(StaticFinalValues.INSTANCETAGNAMESITE);
            List<Double> scores = result.getPredictions(acc);

            // The proteins without scores will be ignored
            // TODO: is this the correct logic?
            if (scores==null) continue;

            Double score = scores.get(site);
            if (Double.isInfinite(score)) {
                score = minScore-Double.MIN_VALUE;
                System.err.println(seq.charAt(site)+site+" in protein "+acc+" has no prediction.");
            }
            label.add(1.0);
            pred.add(score);
        }

        for (Instance ins : instances_unlabeled) {
            Protein protein = (Protein)ins.getInstanceTag().getTag(StaticFinalValues.INSTANCETAGNAMEPROTEIN);
            String acc = protein.getAccession();
            String seq = protein.getSequence();
            int site = (Integer)ins.getInstanceTag().getTag(StaticFinalValues.INSTANCETAGNAMESITE);
            List<Double> scores = result.getPredictions(acc);

            // The proteins without scores will be ignored
            // TODO: is this the correct logic?
            if (scores==null) continue;
            
            Double score = scores.get(site);
            if (Double.isInfinite(score)) {
                score = minScore-Double.MIN_VALUE;
                System.err.println(seq.charAt(site)+site+" in protein "+acc+" has no prediction.");
            }
            label.add(-1.0);
            pred.add(score);
        }

        if (label.isEmpty())
            return false;

        ROC roc = new ROC(label, pred);
        ResultInterpreter ri = new ResultInterpreter(roc);
        result.setResultInterpreter(ri);
        return true;
    }
}
